home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / human interface toolbox / gridwindowgrow / growtogrid.c < prev   
Encoding:
C/C++ Source or Header  |  2000-06-23  |  28.0 KB  |  824 lines

  1. /*
  2.     File:        GrowToGrid.c
  3.  
  4.     Contains:     This snippet shows how to grow a window constrained to a grid (i.e.
  5.                 only allow a window to grow or shrink by 30 pixels, or whatever).
  6.  
  7.                 Now, you might think that using something like DragHook (see the Window 
  8.                 Manager documentation) would be the best way to approach this.  Well, I
  9.                    personally don't think so, and a lot of my pragmatic (i.e. those who
  10.                 like to ship products instead of talking about them) friends agree.  The
  11.                 easiest way to do this is just to write a small MyGrowWIndow function
  12.                 and use that. 
  13.  
  14.                 Or, even better, just grab this one demonstrated here, and you're even more
  15.                 pragmatic than I!
  16.  
  17.     Written by: C.K. Haun    
  18.  
  19.     Copyright:    Copyright © 1994-1999 by Apple Computer, Inc., All Rights Reserved.
  20.  
  21.                 You may incorporate this Apple sample source code into your program(s) without
  22.                 restriction. This Apple sample source code has been provided "AS IS" and the
  23.                 responsibility for its operation is yours. You are not permitted to redistribute
  24.                 this Apple sample source code as "Apple sample source code" after having made
  25.                 changes. If you're going to re-distribute the source, we require that you make
  26.                 it clear in the source that the code was descended from Apple sample source
  27.                 code, but that you've made changes.
  28.  
  29.     Change History (most recent first):
  30.                 8/6/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  31. */
  32. #include <fonts.h>
  33. #include <dialogs.h>
  34. #include <Desk.h>
  35. #include <diskinit.h>
  36. #include <resources.h>
  37. #include <toolutils.h>
  38. #include <GestaltEqu.h>
  39. #include <Balloons.h>
  40. #include <SegLoad.h>
  41. #include <TextUtils.h>
  42.  
  43. #define kExtremeNeg -32768
  44. #define kExtremePos (32767 - 1) /* required to address an old region bug, see develop 20 Q&As */
  45.  
  46. /* prototypes */
  47. void    DrawIndString(short resID,short index);
  48. void MyGrowWindow(WindowPtr theWindow);
  49. void InitalizeApp(void);
  50. void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
  51. void DrawMain(WindowPtr drawIt);
  52. Boolean DoSelected(long val);
  53. void SizeMain(WindowPtr theWindow);
  54. void InitAEStuff(void);
  55. void DoHighLevel(EventRecord *AERecord);
  56. void DoDaCall(MenuHandle themenu, long theit);
  57. void DoDocumentClick(WindowPtr theWindow);
  58. void DoGridDialog(void);
  59. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem);
  60. pascal OSErr AEOpenHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
  61. pascal OSErr AEOpenDocHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
  62. pascal OSErr AEPrintHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
  63. pascal OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
  64. void SampleHelpDialog(void);
  65. WindowPtr AddNewWindow(short theID);
  66. WindowPtr FindWindowByKind(short kindToFind);
  67. void PullRect (Rect    *someRect);
  68.  
  69. void NilProc(void);
  70.  
  71. /* one external */
  72. #ifdef applec
  73.     extern void _DataInit();                                    /* this is the C initialization code */
  74. #endif
  75.  
  76. /* defines and enums */
  77. /* windows */
  78. enum  {
  79.     kDocumentWindow = 1000, kDocWindow = 128
  80. };
  81. /* menu enums */
  82. enum  {
  83.     kMBarID = 128, kAppleMenu = 128, kFileMenu = 129, kEditMenu = 130, kToolsMenu = 131
  84. };
  85. enum  {
  86.     kResumeMask = 1,                                        /* bit of message field for resume vs. suspend */
  87.     kHelpString = 128
  88. };
  89. /* file menu enums */
  90. enum  {
  91.     kNewItem = 1, kOpenItem, kCloseItem, kSaveItem, kSaveAsItem, kFileBlank1, kPageSetupItem, kPrintItem, kFileBlank2, kQuitItem
  92. };
  93.  
  94. enum  {
  95.     kGridDialogItem = 1
  96. };
  97.  
  98. /* alerts and dialogs */
  99.  
  100. enum  {
  101.     kBadSystem = 130, kSampHelp = 129, kAboutBox = 128, kGridDialog = 131
  102. };
  103.  
  104. enum  {
  105.     kGridDialogMenuItem = 1, kGridEditLine = 4
  106. };
  107.  
  108. enum  {
  109.     kMinHeight = 200
  110. };
  111.  
  112. enum {kGenStrings = 128,kSayCurrentGrid=1,kSayChangeGrid
  113. };
  114.  
  115. #define ABS(A) ((A < 0) ? (A*-1):A)
  116.  
  117. /* structs */
  118. struct AEinstalls {
  119.     AEEventClass            theClass;
  120.     AEEventID                theEvent;
  121.     AEEventHandlerProcPtr    theProc;
  122. };
  123. typedef struct AEinstalls AEinstalls;
  124.  
  125.  
  126. /* windowControl is the structure attached to every window I create (in the refCon */
  127. /* field) that contains all the information I need to know about the window. */
  128. /* this one is really simple */
  129. struct windowControl {
  130.     unsigned long windowID;                                 /* master ID number for section recording */
  131.     ProcPtr drawMe;                                         /* content drawing procedure pointer */
  132.     ProcPtr clickMe;                                        /* content click routine */
  133.     ProcPtr saveMe;                                         /* document save procedure pointer */
  134.     ProcPtr closeMe;                                        /* document close procedure pointer */
  135.     ProcPtr sizeMe;
  136.     AliasHandle fileAliasHandle;                            /* alias for this document */
  137.     Boolean windowDirty;
  138.     long windowIndex;                                       /* for AppleEvent information */
  139.     
  140. };
  141. typedef struct windowControl windowControl, *windowCPtr, **windowCHandle;
  142.  
  143. /* globals */
  144. Boolean gQuit, gInBackground;
  145. Boolean dragIn;
  146. EventRecord gERecord;
  147. ProcessSerialNumber gOurSN;
  148. short gHelpItem;
  149. short gGridIncrement = 30;                                  // start at 30
  150.  
  151. #pragma segment Main
  152. void main()
  153. {
  154.     
  155.     WindowPtr twindow;
  156.     short fHit;
  157.     windowCHandle tempWCH;
  158.         
  159.     #ifdef applec    
  160.         UnloadSeg((Ptr)_DataInit);                              /* throw out C setup code */
  161.     #endif
  162.     
  163.     InitalizeApp();
  164.     UnloadSeg((Ptr)InitalizeApp);                           /* get rid of my initialization code */
  165.     /* start running */
  166.     do {
  167.     
  168.         WaitNextEvent(everyEvent, &gERecord, 30, nil);
  169.     
  170.         switch (gERecord.what) {
  171.  
  172.             case nullEvent:
  173.                 /* no nul processing in this sample */
  174.                 break;
  175.  
  176.             case updateEvt:
  177.                 /* at update, draw the window */
  178.                 tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
  179.                     (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
  180.                 
  181.                 break;
  182.                 
  183.             case mouseDown:
  184.                 /* first see where the hit was */
  185.                 fHit = FindWindow(gERecord.where, &twindow);
  186.                 
  187.                 switch (fHit) {
  188.  
  189.                     case inDesk:                            /* if they hit in desk, then the process manager */
  190.                         break;                              /* will switch us out, we don't need to do anything */
  191.  
  192.                     case inMenuBar:
  193.                         DoSelected(MenuSelect(gERecord.where));
  194.                         break;
  195.                         
  196.                     case inSysWindow:
  197.                         /* pass to the system */
  198.                         SystemClick(&gERecord, twindow);
  199.                         break;
  200.  
  201.                     case inContent:
  202.                         /* Handle content and control clicks here */
  203.                         if (FrontWindow()) {                /* don't do this unless we have a window open, silly */
  204.                             windowCHandle clicker;
  205.                             clicker = (windowCHandle)GetWRefCon(twindow);
  206.                             /* jump to the content function stored for this window */
  207.                             HLock((Handle)clicker);         /* lock it down so things don't get stupid */
  208.                             (ProcPtr)((*clicker)->clickMe)(twindow);
  209.                             HUnlock((Handle)clicker);       /* all done */
  210.                         }
  211.                         break;
  212.  
  213.                     case inDrag:
  214.                         if (twindow == FrontWindow())
  215.                             DragWindow(twindow, gERecord.where, &qd.screenBits.bounds);
  216.                         break;
  217.  
  218.                     case inGrow:
  219.                         /* Call GrowWindow here if you have a grow box */
  220.                         SetPort(twindow);
  221.                         MyGrowWindow(twindow);
  222.                         break;
  223.  
  224.                     case inGoAway:
  225.                         /* Click in Close box */
  226.                         if (TrackGoAway(twindow, gERecord.where))
  227.                             (ProcPtr)((*(windowCHandle)((WindowPeek)twindow)->refCon)->closeMe)(twindow);
  228.                         
  229.                         break;
  230.  
  231.                     case inZoomIn:
  232.                     case inZoomOut:
  233.                         if (TrackBox(twindow, gERecord.where, fHit)) {
  234.                             windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow);
  235.                             SetPort(twindow);
  236.                             
  237.                             ZoomWindow(twindow, fHit, true);
  238.                             InvalRect(&twindow->portRect);
  239.                             (ProcPtr)((*tempWCH)->sizeMe)(twindow);
  240.                         }
  241.                 } /* end mouseDown case */
  242.  
  243.             case mouseUp:
  244.                 /* don't care */
  245.                 break;
  246.  
  247.                 /* same action for key or auto key */
  248.             case keyDown:
  249.             case autoKey:
  250.                 if (gERecord.modifiers & cmdKey)
  251.                     DoSelected(MenuKey(gERecord.message & charCodeMask));
  252.                 break;
  253.  
  254.             case keyUp:
  255.                 /* don't care */
  256.                 break;
  257.  
  258.             case diskEvt:
  259.                 /* I don't do anything special for disk events, this just passes them */
  260.                 /* to a function that checks for an error on the mount */
  261.                 DoDiskEvents(gERecord.message);
  262.                 break;
  263.  
  264.             case activateEvt:
  265.                 if (gERecord.modifiers & activeFlag) {
  266.                     tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
  267.                     (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
  268.                 }
  269.                 break;
  270.  
  271.             case 10:
  272.                 /* don't care */
  273.                 break;
  274.  
  275.             case 11:
  276.                 /* don't care */
  277.                 break;
  278.  
  279.             case 15:
  280.                 switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
  281.                     case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
  282.                         gInBackground = (gERecord.message & kResumeMask) == 0;
  283.                         break;
  284.                 }
  285.                 break;
  286.  
  287.                 /* This dispatches high level events (AppleEvents, for example) */
  288.                 /* to our dispatch routine. This is NEW in the event loop for */
  289.                 /* System 7 */
  290.             case kHighLevelEvent:
  291.                 DoHighLevel(&gERecord);
  292.                 break;
  293.  
  294.             default:
  295.                 break;
  296.                 
  297.         }
  298.     }while (gQuit != true);
  299.     
  300. }
  301.  
  302. /* DoDaCall opens the requested DA. It's here as a seperate routine if you'd */
  303. /* like to perform some action or just know when a DA is opened in your */
  304. /* layer. Can be handy to track memory problems when a DA is opened */
  305. /* with an Option-open */
  306. void DoDaCall(MenuHandle themenu, long theit)
  307. {
  308.     long qq;
  309.     Str255 DAname;
  310.     GetMenuItemText(themenu, theit, DAname);
  311.     qq = OpenDeskAcc((ConstStr255Param)&DAname);
  312. }
  313.  
  314. /* end DoDaCall */
  315.  
  316. /* DoDiskEvents just checks the error code from the disk mount, */
  317. /* and puts up the 'Format' dialog (through DIBadMount) if need be */
  318. /* You can do much more here if you care about what disks are */
  319. /* in the drive */
  320. void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
  321. {
  322.     short hival, loval, tommy;
  323.     Point fredpoint =  {
  324.         40, 40
  325.     };
  326.     hival = HiWord(dinfo);
  327.     loval = LoWord(dinfo);
  328.     if (hival != noErr)                                     /* something happened */ {
  329.         tommy = DIBadMount(fredpoint, dinfo);
  330.     }
  331. }
  332.  
  333. /* draws my window. Pretty simple */
  334. void DrawMain(WindowPtr drawIt)
  335. {
  336.     RgnHandle tempRgn;
  337.     Rect scratchRect;
  338.     Str31 tempString;
  339.     BeginUpdate(drawIt);
  340.     SetPort(drawIt);
  341.     EraseRect(&drawIt->portRect);
  342.     MoveTo(10, 17);
  343.     DrawIndString(kGenStrings,kSayCurrentGrid);
  344.     NumToString(gGridIncrement, tempString);
  345.     DrawString(tempString);
  346.     MoveTo(10, 37);
  347.     DrawIndString(kGenStrings,kSayChangeGrid);
  348.     
  349.     scratchRect = drawIt->portRect;
  350.     scratchRect.top = scratchRect.bottom - 15;
  351.     scratchRect.left = scratchRect.right - 15;
  352.     tempRgn = NewRgn();
  353.     GetClip(tempRgn);
  354.     ClipRect(&scratchRect);
  355.     DrawGrowIcon(drawIt);
  356.     SetClip(tempRgn);
  357.     DisposeRgn(tempRgn);
  358.     
  359.     EndUpdate(drawIt);
  360. }
  361.  
  362. /* my menu action taker. It returns a Boolean which I usually ignore, but it */
  363. /* mught be handy someday */
  364. Boolean DoSelected(long val)
  365. {
  366.     short loval, hival;
  367.     Boolean returnVal = false;
  368.     loval = LoWord(val);
  369.     hival = HiWord(val);
  370.     
  371.     switch (hival) {                                        /* switch off the menu number selected */
  372.         case kAppleMenu:                                    /* Apple menu */
  373.             if (loval != 1) {                               /* if this was not About, it's a DA */
  374.                 DoDaCall(GetMenuHandle(kAppleMenu), loval);
  375.             } else {
  376.                 Alert(kAboutBox, nil);                      /* do about box */
  377.             }
  378.             returnVal = true;
  379.             break;
  380.         case kFileMenu:                                     /* File menu */
  381.             switch (loval) {
  382.                 case kQuitItem:
  383.                     gQuit = true;                           /* only item */
  384.                     returnVal = true;
  385.                     break;
  386.                 default:
  387.                     break;
  388.             }
  389.             break;
  390.         case kEditMenu:
  391.             /* edit menu junk */
  392.             /* don't care */
  393.             break;
  394.         case kToolsMenu:
  395.         case kGridDialogItem:
  396.             DoGridDialog();
  397.             break;
  398.             break;
  399.         case kHMHelpMenuID:                                 /* Defined in Balloons.h */
  400.             /* I only care about this item. If anything else is returned here, I don't know what */
  401.             /* it is, so I leave it alone. Remember, the Help Manager chapter says that */
  402.             /* Apple reserves the right to add and change things in the Help menu */
  403.             if (loval == gHelpItem)
  404.                 SampleHelpDialog();
  405.             break;
  406.             
  407.     }
  408.     HiliteMenu(0);
  409.     return(returnVal);
  410. }
  411.  
  412. void DoDocumentClick(WindowPtr theWindow)
  413. {
  414. #pragma unused (theWindow )
  415. }
  416.  
  417. /* InitAEStuff installs my appleevent handlers */
  418. void InitAEStuff(void)
  419. {
  420.     static AEinstalls HandlersToInstall[] =
  421.     {
  422.         { kCoreEventClass, kAEOpenApplication,    AEOpenHandler        },
  423.         { kCoreEventClass, kAEQuitApplication,    AEQuitHandler        },
  424.         { kCoreEventClass, kAEOpenDocuments,    AEOpenDocHandler    },
  425.         { kCoreEventClass, kAEPrintDocuments,    AEPrintHandler        }
  426.     };
  427.     
  428.     OSErr aevtErr = noErr;
  429.     long aLong = 0;
  430.     Boolean gHasAppleEvents = false;
  431.  
  432.     /* Check this machine for AppleEvents. If they are not here (ie not 7.0)
  433.     * then we exit */
  434.  
  435.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
  436.  
  437.     /* The following series of calls installs all our AppleEvent Handlers.
  438.     * These handlers are added to the application event handler list that 
  439.     * the AppleEvent manager maintains. So, whenever an AppleEvent happens
  440.     * and we call AEProcessEvent, the AppleEvent manager will check our
  441.     * list of handlers and dispatch to it if there is one.
  442.     */
  443.  
  444.     if (gHasAppleEvents) {
  445.         register qq;
  446.         for (qq = 0; qq < ((sizeof(HandlersToInstall) / sizeof(AEinstalls))); qq++) {
  447.             aevtErr = AEInstallEventHandler
  448.                 (HandlersToInstall[qq].theClass, HandlersToInstall[qq].theEvent,
  449.                     NewAEEventHandlerProc (HandlersToInstall[qq].theProc), 0, false);
  450.             if (aevtErr) {
  451.                 ExitToShell();                              /* just fail, baby */
  452.             }
  453.         }
  454.     } else {
  455.         ExitToShell();
  456.     }
  457. }
  458.  
  459. /* end InitAEStuff */
  460. /* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
  461. /* easy for me to say, huh? */
  462. void DoHighLevel(EventRecord *AERecord)
  463. {
  464.     
  465.     AEProcessAppleEvent(AERecord);
  466.     
  467. }
  468.  
  469. /* end DoHighLevel */
  470.  
  471. /* This is the standard Open Application event. */
  472. pascal OSErr AEOpenHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
  473. {
  474. #pragma unused (messagein,reply,refIn)
  475.     /* we of course don't do anything here in this simple app */
  476.     /* except open our window */
  477.     AddNewWindow(128);
  478.     return(noErr);
  479. }
  480.  
  481. /* end AEOpenHandler */
  482.  
  483. /* Open Doc, opens our documents. Remember, this can happen at application start AND */
  484. /* anytime else. If your app is up and running and the user goes to the desktop, hilites one */
  485. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  486. /* handler will get called. Which means you don't do any initialization of globals here, or */
  487. /* anything else except open then doc. */
  488. /* SO-- Do NOT assume that you are at app start time in this */
  489. /* routine, or bad things will surely happen to you. */
  490.  
  491. pascal OSErr AEOpenDocHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
  492. {
  493. #pragma unused (messagein,refIn,reply)
  494.     /* we of course don't do anything here */
  495.     return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
  496. }
  497.  
  498. pascal OSErr AEPrintHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
  499. {                                                           /* no printing handler in yet, so we'll ignore this */
  500.     /* the operation is functionally identical to the ODOC event, with the additon */
  501.     /* of calling your print routine. */
  502. #pragma unused (messagein,refIn,reply)
  503.     /* we of course don't do anything here */
  504.     return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
  505. }
  506.  
  507. /* Standard Quit event handler, to handle a Quit event from the Finder, for example. */
  508. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life. */
  509. pascal OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
  510. {
  511. #pragma unused (messagein,refIn,reply)
  512.     
  513.     /* prepQuit sets the Stop flag for us. It does _NOT_ quit, you */
  514.     /* should NEVER quit from an AppleEvent handler. Calling */
  515.     /* ExitToShell here would blow things up */
  516.     gQuit = true;
  517.     return(noErr);
  518. }
  519.  
  520. /* This is my sample help dialog. Does not do anything, expand as you need */
  521. void SampleHelpDialog(void)
  522. {
  523.     DialogPtr tdial = GetNewDialog(kSampHelp, nil, (WindowPtr)-1);
  524.     short itemhit = 0;
  525.     while (itemhit != 1) {
  526.         ModalDialog(NewModalFilterProc(nil), &itemhit);
  527.     }
  528.     DisposeDialog(tdial);
  529. }
  530.  
  531.  
  532. #pragma segment Initialize
  533. void InitalizeApp(void)
  534. {
  535.     MenuHandle helpHandle;
  536.     Handle myMenuBar;
  537.     StringHandle helpString;
  538.     short count;
  539.     long vers;
  540.     MaxApplZone();
  541.     InitGraf((Ptr)&qd.thePort);
  542.     InitFonts();
  543.     InitWindows();
  544.     InitMenus();
  545.     TEInit();
  546.     InitDialogs(nil);
  547.     InitCursor();
  548.     /* Check system version */
  549.     Gestalt(gestaltSystemVersion, &vers);
  550.     vers = (vers >> 8) & 0xf;                               /* shift result over and mask out major version number */
  551.     if (vers < 7) {
  552.         StopAlert(kBadSystem, nil);
  553.         ExitToShell();
  554.     }
  555.     InitAEStuff();
  556.     /* set up my menu junk */
  557.     myMenuBar = GetNewMBar(kMBarID);
  558.     SetMenuBar(myMenuBar);
  559.     AppendResMenu(GetMenuHandle(kAppleMenu), 'DRVR');
  560.     /* now install my Help menu item in the Help Manager's menu */
  561.     HMGetHelpMenuHandle(&helpHandle);                       /* Get the Hlpe menu handle */
  562.     count = CountMItems(helpHandle);                        /* How many items are there? */
  563.     helpString = GetString(kHelpString);                    /* get my help string */
  564.     DetachResource((Handle)helpString);                             /* detach it */
  565.     HNoPurge((Handle)helpString);
  566.     MoveHHi((Handle)helpString);
  567.     HLock((Handle)helpString);
  568.     InsertMenuItem(helpHandle, (ConstStr255Param)helpString, count + 1);       /* insert my item in the Help menu */
  569.     gHelpItem = CountMItems(helpHandle);                    /* The number of the item */
  570.     
  571.     DrawMenuBar();
  572.     GetCurrentProcess(&gOurSN);                             /* Get our process serial number for later use, if needed */
  573.     
  574. }
  575.  
  576.  
  577. #pragma segment Main
  578. WindowPtr AddNewWindow(short theID)
  579. {
  580.     windowCHandle setControls;
  581.     WindowPtr tempWP;
  582.     short cnt = 0;
  583.     tempWP = GetNewWindow(theID, 0, (WindowPtr)-1);         /* get a new window */
  584.     SetPort(tempWP);
  585.     ((WindowPeek)tempWP)->windowKind = kDocumentWindow;     /* mark it as a document window */
  586.     setControls = (windowCHandle)NewHandleClear(sizeof(windowControl));     /* add our control structure to it */
  587.     SetWRefCon(tempWP, (long)setControls);                  /* stop stuffing refCon directly <ckh 1.0.3> */
  588.     HLock((Handle)setControls);                             /* lock it down while we fill it*/
  589.     
  590.     /* add pointers to our procedures for drawing, saving, and closing */
  591.     /* This way, all I need is one dispatch point for drawing, closing */
  592.     /* or whatever, I don't have to case off the window kind to go to the */
  593.     /* correct routine. Kinda like object-oriented programming, but I won't */
  594.     /* admit that. */
  595.     (*setControls)->drawMe = (ProcPtr)DrawMain;
  596.     (*setControls)->saveMe = (ProcPtr)NilProc;
  597.     (*setControls)->closeMe = (ProcPtr)NilProc;
  598.     (*setControls)->clickMe = (ProcPtr)DoDocumentClick;
  599.     (*setControls)->sizeMe = (ProcPtr)SizeMain;
  600.     /* now initialize all our required handles */
  601.     return(tempWP);
  602. }
  603.  
  604. void SizeMain(WindowPtr theWindow)
  605. {
  606.     WindowPtr tempWP;
  607.     GetPort(&tempWP);
  608.     InvalRect(&theWindow->portRect);
  609.     SetPort(tempWP);
  610. }
  611.  
  612. void NilProc(void)
  613. {
  614.     
  615. }
  616.  
  617. // This will grid a window grow to a specific increment
  618.  
  619. void PullRect(Rect *startRect)
  620. {
  621.     
  622.     Rect *oldRect;
  623.     Point endPoint;
  624.     Boolean hreversed = false;
  625.     Boolean vreversed = false;
  626.     short tempH, tempV;
  627.     short divBy20h, divBy20v;
  628.     /* set up */
  629.     oldRect = startRect;
  630.     PenMode(srcXor);                                        /* So we can rubberband */
  631.     PenPat(&qd.gray);
  632.     FrameRect(startRect);
  633.     divBy20h = startRect->right;
  634.     divBy20v = startRect->bottom;
  635.     
  636.     
  637.     while (StillDown()) {                                   /* Keep doing this as long as the */
  638.         
  639.         /* user keeps the mouse down */
  640.         GetMouse(&endPoint);                                /* Current mouse position in local */
  641.         // see if it's on a  grid point
  642.         
  643.         tempH = ABS(endPoint.h - divBy20h) / gGridIncrement;
  644.         tempV = ABS(endPoint.v - divBy20v) / gGridIncrement;
  645.         // normalize to our grid values. We'll always go outwards as better
  646.         if ((tempH * gGridIncrement) != ABS(endPoint.h - divBy20h)) {
  647.             // shove out based on the remainer
  648.             endPoint.h = (((endPoint.h)/gGridIncrement)*gGridIncrement)+gGridIncrement;
  649.         }
  650.         if ((tempV * gGridIncrement) != ABS(endPoint.v - divBy20v)) {
  651.             endPoint.v = (((endPoint.v)/gGridIncrement)*gGridIncrement)+gGridIncrement;
  652.             
  653.         }
  654. // If things reversed, we have to make sure that we don't try
  655. // and grid the origin point of the drag, cuz that would be weird
  656.  
  657.             if (hreversed) {
  658.                 /* see if the rectangle flipped first */
  659.                 if (endPoint.h > startRect->right) {
  660.                     /* they flipped back */
  661.                     hreversed = false;                      /* and ignore this move */
  662.                 } else {
  663.                     /* still reversed */
  664.                     startRect->left = endPoint.h;
  665.                 }
  666.             } else {
  667.                 if (endPoint.h < startRect->left) {
  668.                     hreversed = true;
  669.  
  670.                 } else {
  671.                     startRect->right = endPoint.h;
  672.                 }
  673.             }
  674.             if (vreversed) {
  675.                 /* see if it flipped first */
  676.                 if (endPoint.v > startRect->bottom) {
  677.                     /* they flipped back */
  678.                     vreversed = false;                      /* and ignore this move */
  679.                 } else {
  680.                     /* still reversed */
  681.                     startRect->top = endPoint.v;
  682.                 }
  683.             } else {
  684.                 if (endPoint.v < startRect->top) {
  685.                     vreversed = true;
  686.                 } else {
  687.                     startRect->bottom = endPoint.v;
  688.                 }
  689.             }
  690.             if (startRect != oldRect) {                    /* redraw the rect only if the mouse moved */
  691.                 FrameRect(oldRect);
  692.                 FrameRect(startRect);                       /* draw the new rect */
  693.                 oldRect = startRect;
  694.             }
  695.         
  696.     }    
  697.     FrameRect(startRect);
  698.     
  699.     PenMode(srcCopy);
  700.     PenPat(&qd.black);
  701. }
  702.  
  703. void MyGrowWindow(WindowPtr theWindow)
  704. {
  705.     PenState oldPen;
  706.     WindowPtr tempWP, WMPort;
  707.     Rect draggingRect = theWindow->portRect;
  708.     Rect wideOpen =  {
  709.         kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos
  710.     };
  711.     RgnHandle oldRgn = NewRgn();
  712.     
  713.     GetPort(&tempWP);
  714.     SetPort(theWindow);
  715.     /* normalize my rectangle into the window manager port coordinates */
  716.     LocalToGlobal((Point *)&draggingRect);
  717.     LocalToGlobal((Point *)&draggingRect.bottom);
  718.     /*  go to the WManager port */
  719.     GetWMgrPort(&WMPort);
  720.     SetPort(WMPort);
  721.     /* save the Window manager pen state since we'll be changing it */
  722.     GetPenState(&oldPen);
  723.     /* localize back */
  724.     GlobalToLocal((Point *)&draggingRect);
  725.     GlobalToLocal((Point *)&draggingRect.bottom);
  726.     
  727.     /* save the current clip region, and set our wide-open clip */
  728.     GetClip(oldRgn);
  729.     ClipRect(&wideOpen);
  730.     /* go to the routine above and do the actual dragging */
  731.     PullRect(&draggingRect);
  732.     
  733.     /* restore the original environment */
  734.     SetClip(oldRgn);
  735.     SetPenState(&oldPen);
  736.     DisposeRgn(oldRgn);
  737.     /* now size the window for the returned rect */
  738.     SetPort(theWindow);
  739.     InvalRect(&theWindow->portRect);
  740.     SizeWindow(theWindow, draggingRect.right - draggingRect.left, draggingRect.bottom - draggingRect.top, true);
  741.     SetPort(tempWP);
  742.     
  743. }
  744.  
  745.  
  746. void DoGridDialog(void)
  747. {
  748.     Str255 tempString;
  749.     WindowPtr tempWP=nil;
  750.     WindowPtr tempPort=nil;
  751.  
  752.     long aLong;
  753.     DialogPtr theDialog = GetNewDialog(kGridDialog, nil, (WindowPtr)-1);
  754.     short itemHit = 0;
  755.     ModalFilterUPP theStdProc=nil;   // inited to nil in case the Get fails
  756.  
  757.     // get some automatic dialog behaviour 
  758.     SetDialogDefaultItem(theDialog,ok);
  759.     SetDialogTracksCursor(theDialog,true);
  760.     GetStdFilterProc(&theStdProc);
  761.  
  762.     // set the item to be the current grid value
  763.  
  764.     NumToString(gGridIncrement, tempString);
  765.     SetDialogItemText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
  766.     
  767.     // spin until they hit OK or Cancel
  768.     while (itemHit != ok && itemHit !=cancel) {
  769.         ModalDialog(theStdProc, &itemHit);
  770.     }
  771.     
  772.     if (itemHit == 1) {
  773.         // they OK'ed their new grid value
  774.         GetDialogItemText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
  775.         StringToNum(tempString, &aLong);
  776.         gGridIncrement = aLong;
  777.     // invalidate our document window so the new value will be refelcted
  778.     tempWP = FindWindowByKind(kDocumentWindow);
  779.     if(tempWP != nil){
  780.         GetPort(&tempPort);
  781.         SetPort(tempWP);
  782.         InvalRect(&tempWP->portRect);
  783.         SetPort(tempPort);
  784.     }
  785.     }
  786.     
  787.     DisposeDialog(theDialog);
  788. }
  789.  
  790. /* gets a handle from a dialog item  */
  791. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
  792. {
  793.     short itemtype;
  794.     Rect itemrect;
  795.     Handle thandle;
  796.     GetDialogItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
  797.     return((ControlHandle)thandle);
  798. }
  799.  
  800. /* end SnatchHandle */
  801.  
  802. /* loads an index string and draws it.  Just a convinice */
  803. void    DrawIndString(short resID,short index)
  804. {
  805. Str255 theString;
  806. GetIndString(theString,resID,index);
  807. DrawString(theString);
  808. }
  809.  
  810. /* returns the first window of specified kind, or nil if none */
  811. WindowPtr FindWindowByKind(short kindToFind)
  812. {
  813. WindowPtr currentWindow = FrontWindow();
  814. while(currentWindow){
  815.     if(((WindowPeek)currentWindow)->windowKind == kindToFind){
  816.         // found it, break
  817.         break;
  818.     } else {
  819.         // go to the next one
  820.         currentWindow = (WindowPtr) ((WindowPeek)currentWindow)->nextWindow;
  821.     }
  822. }
  823. return ( currentWindow );
  824. }